package com.qzh.QVM.Simulator;

import lombok.Data;

import java.util.ArrayList;

/**
 * 内存模拟器管理者
 */
@Data
public class Manager {
    private static Manager instance;
    /**
     * 储存所有内存的LIST
     */
    private ArrayList<Block> totalList;
    /**
     * 设计的总容量，不能用size()
     */
    private int maxSize;
    /**
     * 当前水位，未用，初始为0
     */
    private int current = 0;
    private Manager(){}
    /**
     * 是否允许跨域操作，敏感行为
     * 一个应用应该只允许操作自己内部的
     */
    private boolean crossField = false;
    /**
     * 当前运行时间
     */
    private int runTime = 0;
    /**
    *  新生代执行清理方法的最小引用次数
     */
    private int youngCleanUsedCount;
    /**
     *  老生代执行清理方法的最小引用次数
     */
    private int oldCleanUsedCount;
    /**
     * 新生代转移到老生代的最小引用次数
     */
    private int youngToOldUsedCount;
    /**
     * 老生代转移到永生代的最小引用次数
     */
    private int oldToEternityUsedCount;


    /**
     * 默认的清理方法，只判断一段时间内的引用次数
     * 只清理新生代、老生代的引用次数不达标的
     * 不会改变其他block
     */
    public void clean(){
        //for循环整个list
        //只判断引用次数是否达标
        for (int i = 0; i <maxSize ; i++) {
                Block block = totalList.get(i);
                switch(block.getType()){
                    case 新生代:
                        //如果是新生代就判断youngCleanUsedCount
                        if(block.getUsedCount()<=youngCleanUsedCount){
                            clearBlock(block);
                        }
                        break;
                    case 老生代:
                        //如果是老生代就判断oldCleanUsedCount
                        if(block.getUsedCount()<=oldCleanUsedCount){
                            clearBlock(block);
                        }
                        break;
                    default:
                        //do nothing

                }
        }
    }

    /**
     * 生代轮转的默认方法，只判断引用次数是否大于要求的次数
     * 将新生代标记转移到老生代
     * 将老生代转移到永生代
     * 将引用清除
     */
    public void circle(){
        for(int i = 0; i < maxSize; i++){
            Block block = totalList.get(i);
            switch(block.getType()){
                case 新生代:
                    if(block.getUsedCount() > youngToOldUsedCount){
                        block.setType(BlockType.老生代);
                        break;
                    }
                case 老生代:
                    if(block.getUsedCount() > oldToEternityUsedCount){
                        block.setType(BlockType.永生代);
                        break;
                    }
                default:
                    //do nothing
                    break;
            }
            block.setUsedCount(0);
            block.setLastTime(0);
        }
    }

    /**
     * 将block归零的方法
     * 用的次数多，所以独立出来
     * @param block
     */
    private void clearBlock(Block block){
        block.setType(BlockType.未使用);
        block.setUsedCount(0);
        block.setData(null);
        block.setOwnerId(null);
        block.setLife(0);
        block.setLastTime(0);
    }


    /**
     * 默认的申请内存block的方法
     * @param size
     * @return
     */
    public ApplyResult applyForBlocks(int id,int size)
    {
        //先判断是否超出总数量
        if(current+size>maxSize)
        {
            return new ApplyResult().setSuccess(false).setStartNumber(-1).setMessage("out of blocks");
        }
        //判断是否允许跨域
        if(!crossField){
            //再判断这些blocks是否id为自身
            for(int i=0;i<size;i++){
                if(this.totalList.get(i).getOwnerId()!=id){
                    return new ApplyResult().setSuccess(false).setStartNumber(-1).setMessage("not your own");
                }
            }
        }

        //最后进行操作
        int temp = current;
            for(int i=0;i<size;i++){
                try{
                   Block block =  this.totalList.get(current);
                    block.setOwnerId(id);
                    block.setLastTime(0);
                    block.setUsedCount(0);
                    block.setType(BlockType.新生代);
                    current++;
                   }
                catch(Exception e){
                   e.getMessage();
                   current  = temp;
                    return new ApplyResult().setSuccess(false).setStartNumber(-1).setMessage("other failed");
                   }
                current++;
        }
        return new ApplyResult().setSuccess(true).setStartNumber(temp).setMessage("success applied");
    }

    /**
     * 获取数据
     * @param id
     * @param position
     * @return
     */
    private Object getData(int id,int position){
        Block block = totalList.get(position);
        Object data = block.getData();
        //引用次数+1
        block.setUsedCount(block.getUsedCount()+1);
        //设置上一次的引用时间
        block.setLastTime(this.runTime);
        return data;
    }

    /**
     * 设置数据
     * @param id
     * @param position
     * @param data
     */
    public void setData(int id,int position,Object data){
        Block block = totalList.get(position);
        //引用次数+1
        block.setUsedCount(block.getUsedCount()+1);
        //设置上一次的引用时间
        block.setLastTime(this.runTime);
        block.setData(data);
    }
    /**
     * 默认的释放block的方法
     * @param start
     * @param size
     * @return 是否成功
     */
    public boolean freeForBlocks(int id,int start,int size){
       if(size<=0){return false;}
        //判断是否允许跨域
        if(!crossField){
            //再判断这些blocks是否id为自身
            for(int i=start;i<=size;i++){
                if(this.totalList.get(i).getOwnerId()!=id){
                    return false;
                }
            }
        }
        //for清空数据，不动current；
        for(int i=start;i<=size;i++){
            //清空数据
            this.totalList.get(i).setOwnerId(null);
            this.totalList.get(i).setData(null);
            this.totalList.get(i).setLastTime(0);
            this.totalList.get(i).setUsedCount(0);
            this.totalList.get(i).setType(BlockType.未使用);
        }

        return false;
    }


    /**
     * 初始化
     * @param maxSize
     */
    public void init(int maxSize){
        this.totalList = new ArrayList<>(maxSize);
        /**
         * 先初始化内存，默认无占用
         */
        for(int i =0;i<maxSize;i++){
            Block block = new Block();
            block.setLife(10);
            block.setType(BlockType.未使用);
            block.setId(i);
            totalList.add(block);
        }
        this.maxSize = maxSize;
    }



    /**
     * 获取唯一单例
     * @return
     */
    public static Manager getInstance(int totalBlockSize) {
        if(instance == null){
            instance = new Manager();
            instance.setTotalList(new ArrayList<>(totalBlockSize));
        }
        return instance;
    }







}
